/*
 *  The RSA public-key cryptosystem
 *
 *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
 *  SPDX-License-Identifier: Apache-2.0
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
 *  not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This file is part of mbed TLS (https://tls.mbed.org)
 */
/*
 *  The following sources were referenced in the design of this implementation
 *  of the RSA algorithm:
 *
 *  [1] A method for obtaining digital signatures and public-key cryptosystems
 *      R Rivest, A Shamir, and L Adleman
 *      http://people.csail.mit.edu/rivest/pubs.html#RSA78
 *
 *  [2] Handbook of Applied Cryptography - 1997, Chapter 8
 *      Menezes, van Oorschot and Vanstone
 *
 *  [3] Malware Guard Extension: Using SGX to Conceal Cache Attacks
 *      Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and
 *      Stefan Mangard
 *      https://arxiv.org/abs/1702.08719v2
 *
 */

#include "crypto_config.h"
#include "crypto_rsa.h"
#include "crypto_oid.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define sc_mbedtls_printf printf

int rsa_rand(void *rng_state, unsigned char *output, size_t len)
{
    size_t i;

    if (rng_state != NULL)
        rng_state = NULL;
    for (i = 0; i < len; ++i)
        output[i] = rand();
#ifdef CONFIG_RSA_DEBUG
    for (i = 0; i < len; ++i)
        output[i] = 0xAA;
#endif
    return (0);
}

/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize(void *v, size_t n)
{
    volatile unsigned char *p = (unsigned char *)v;
    while (n--)
        *p++ = 0;
}

/*
 * Initialize an RSA context
 */
void sc_mbedtls_rsa_init(sc_mbedtls_rsa_context *ctx, int padding, int hash_id)
{
    memset(ctx, 0, sizeof(sc_mbedtls_rsa_context));

    sc_mbedtls_rsa_set_padding(ctx, padding, hash_id);
}

/*
 * Set padding for an existing RSA context
 */
void sc_mbedtls_rsa_set_padding(sc_mbedtls_rsa_context *ctx, int padding, int hash_id)
{
    ctx->padding = padding;
    ctx->hash_id = hash_id;
}

#if defined(MBEDTLS_GENPRIME)

/*
 * Generate an RSA keypair
 */
int sc_mbedtls_rsa_gen_key(sc_mbedtls_rsa_context *ctx,
                            int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
                            unsigned int nbits, int exponent)
{
    int             ret;
    sc_mbedtls_mpi P1, Q1, H, G;

    if (f_rng == NULL || nbits < 128 || exponent < 3)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    if (nbits % 2)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    sc_mbedtls_mpi_init(&P1);
    sc_mbedtls_mpi_init(&Q1);
    sc_mbedtls_mpi_init(&H);
    sc_mbedtls_mpi_init(&G);

    /*
     * find primes P and Q with Q < P so that:
     * GCD( E, (P-1)*(Q-1) ) == 1
     */
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_lset(&ctx->E, exponent));

    do {
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_gen_prime(&ctx->P, nbits >> 1, 0, f_rng, p_rng));

        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_gen_prime(&ctx->Q, nbits >> 1, 0, f_rng, p_rng));

        if (sc_mbedtls_mpi_cmp_mpi(&ctx->P, &ctx->Q) == 0)
            continue;

        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&ctx->N, &ctx->P, &ctx->Q));
        if (sc_mbedtls_mpi_bitlen(&ctx->N) != nbits)
            continue;

        if (sc_mbedtls_mpi_cmp_mpi(&ctx->P, &ctx->Q) < 0)
            sc_mbedtls_mpi_swap(&ctx->P, &ctx->Q);

        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_sub_int(&P1, &ctx->P, 1));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_sub_int(&Q1, &ctx->Q, 1));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&H, &P1, &Q1));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_gcd(&G, &ctx->E, &H));
    } while (sc_mbedtls_mpi_cmp_int(&G, 1) != 0);

    /*
     * D  = E^-1 mod ((P-1)*(Q-1))
     * DP = D mod (P - 1)
     * DQ = D mod (Q - 1)
     * QP = Q^-1 mod P
     */
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_inv_mod(&ctx->D, &ctx->E, &H));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&ctx->DP, &ctx->D, &P1));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&ctx->DQ, &ctx->D, &Q1));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_inv_mod(&ctx->QP, &ctx->Q, &ctx->P));

    ctx->len = (sc_mbedtls_mpi_bitlen(&ctx->N) + 7) >> 3;

cleanup:

    sc_mbedtls_mpi_free(&P1);
    sc_mbedtls_mpi_free(&Q1);
    sc_mbedtls_mpi_free(&H);
    sc_mbedtls_mpi_free(&G);

    if (ret != 0) {
        sc_mbedtls_rsa_free(ctx);
        return (SC_MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret);
    }

    return (0);
}

#endif /* MBEDTLS_GENPRIME */

/*
 * Check a public RSA key
 */
int sc_mbedtls_rsa_check_pubkey(const sc_mbedtls_rsa_context *ctx)
{
    if (!ctx->N.p || !ctx->E.p)
        return (SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED);

    if ((ctx->N.p[0] & 1) == 0 || (ctx->E.p[0] & 1) == 0)
        return (SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED);

    if (sc_mbedtls_mpi_bitlen(&ctx->N) < 128 ||
        sc_mbedtls_mpi_bitlen(&ctx->N) > SC_MBEDTLS_MPI_MAX_BITS)
        return (SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED);

    if (sc_mbedtls_mpi_bitlen(&ctx->E) < 2 || sc_mbedtls_mpi_cmp_mpi(&ctx->E, &ctx->N) >= 0)
        return (SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED);

    return (0);
}

/*
 * Check a private RSA key
 */
int sc_mbedtls_rsa_check_privkey(const sc_mbedtls_rsa_context *ctx)
{
    int             ret;
    sc_mbedtls_mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP;

    if ((ret = sc_mbedtls_rsa_check_pubkey(ctx)) != 0)
        return (ret);

    if (!ctx->P.p || !ctx->Q.p || !ctx->D.p)
        return (SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED);

    sc_mbedtls_mpi_init(&PQ);
    sc_mbedtls_mpi_init(&DE);
    sc_mbedtls_mpi_init(&P1);
    sc_mbedtls_mpi_init(&Q1);
    sc_mbedtls_mpi_init(&H);
    sc_mbedtls_mpi_init(&I);
    sc_mbedtls_mpi_init(&G);
    sc_mbedtls_mpi_init(&G2);
    sc_mbedtls_mpi_init(&L1);
    sc_mbedtls_mpi_init(&L2);
    sc_mbedtls_mpi_init(&DP);
    sc_mbedtls_mpi_init(&DQ);
    sc_mbedtls_mpi_init(&QP);

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&PQ, &ctx->P, &ctx->Q));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&DE, &ctx->D, &ctx->E));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_sub_int(&P1, &ctx->P, 1));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_sub_int(&Q1, &ctx->Q, 1));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&H, &P1, &Q1));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_gcd(&G, &ctx->E, &H));

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_gcd(&G2, &P1, &Q1));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_div_mpi(&L1, &L2, &H, &G2));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&I, &DE, &L1));

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&DP, &ctx->D, &P1));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&DQ, &ctx->D, &Q1));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_inv_mod(&QP, &ctx->Q, &ctx->P));
    /*
     * Check for a valid PKCS1v2 private key
     */
    if (sc_mbedtls_mpi_cmp_mpi(&PQ, &ctx->N) != 0 || sc_mbedtls_mpi_cmp_mpi(&DP, &ctx->DP) != 0 ||
        sc_mbedtls_mpi_cmp_mpi(&DQ, &ctx->DQ) != 0 ||
        sc_mbedtls_mpi_cmp_mpi(&QP, &ctx->QP) != 0 || sc_mbedtls_mpi_cmp_int(&L2, 0) != 0 ||
        sc_mbedtls_mpi_cmp_int(&I, 1) != 0 || sc_mbedtls_mpi_cmp_int(&G, 1) != 0) {
        ret = SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
    }

cleanup:
    sc_mbedtls_mpi_free(&PQ);
    sc_mbedtls_mpi_free(&DE);
    sc_mbedtls_mpi_free(&P1);
    sc_mbedtls_mpi_free(&Q1);
    sc_mbedtls_mpi_free(&H);
    sc_mbedtls_mpi_free(&I);
    sc_mbedtls_mpi_free(&G);
    sc_mbedtls_mpi_free(&G2);
    sc_mbedtls_mpi_free(&L1);
    sc_mbedtls_mpi_free(&L2);
    sc_mbedtls_mpi_free(&DP);
    sc_mbedtls_mpi_free(&DQ);
    sc_mbedtls_mpi_free(&QP);

    if (ret == SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED)
        return (ret);

    if (ret != 0)
        return (SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + ret);

    return (0);
}

/*
 * Check if contexts holding a public and private key match
 */
int sc_mbedtls_rsa_check_pub_priv(const sc_mbedtls_rsa_context *pub,
                                   const sc_mbedtls_rsa_context *prv)
{
    if (sc_mbedtls_rsa_check_pubkey(pub) != 0 || sc_mbedtls_rsa_check_privkey(prv) != 0) {
        return (SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED);
    }

    if (sc_mbedtls_mpi_cmp_mpi(&pub->N, &prv->N) != 0 ||
        sc_mbedtls_mpi_cmp_mpi(&pub->E, &prv->E) != 0) {
        return (SC_MBEDTLS_ERR_RSA_KEY_CHECK_FAILED);
    }

    return (0);
}

/*
 * Do an RSA public key operation
 */
int sc_mbedtls_rsa_public(sc_mbedtls_rsa_context *ctx, const unsigned char *input,
                           unsigned char *output)
{
    int             ret;
    size_t          olen;
    sc_mbedtls_mpi T;

    sc_mbedtls_mpi_init(&T);

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_binary(&T, input, ctx->len));

    if (sc_mbedtls_mpi_cmp_mpi(&T, &ctx->N) >= 0) {
        ret = SC_MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
        goto cleanup;
    }

    olen = ctx->len;
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_exp_mod(&T, &T, &ctx->E, &ctx->N, &ctx->RN));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_write_binary(&T, output, olen));

cleanup:

    sc_mbedtls_mpi_free(&T);

    if (ret != 0)
        return (SC_MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret);

    return (0);
}

/*
 * Generate or update blinding values, see section 10 of:
 *  KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
 *  DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer
 *  Berlin Heidelberg, 1996. p. 104-113.
 */
static int rsa_prepare_blinding(sc_mbedtls_rsa_context *ctx,
                                int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
    int ret, count = 0;

    if (ctx->Vf.p != NULL) {
        /* We already have blinding values, just update them by squaring */
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&ctx->Vi, &ctx->Vi, &ctx->Vi));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&ctx->Vi, &ctx->Vi, &ctx->N));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &ctx->Vf));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->N));

        goto cleanup;
    }

    /* Unblinding value: Vf = random number, invertible mod N */
    do {
        if (count++ > 10)
            return (SC_MBEDTLS_ERR_RSA_RNG_FAILED);

        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_fill_random(&ctx->Vf, ctx->len - 1, f_rng, p_rng));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_gcd(&ctx->Vi, &ctx->Vf, &ctx->N));
    } while (sc_mbedtls_mpi_cmp_int(&ctx->Vi, 1) != 0);

    /* Blinding value: Vi =  Vf^(-e) mod N */
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_inv_mod(&ctx->Vi, &ctx->Vf, &ctx->N));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_exp_mod(&ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN));

cleanup:
    return (ret);
}

/*
 * Exponent blinding supposed to prevent side-channel attacks using multiple
 * traces of measurements to recover the RSA key. The more collisions are there,
 * the more bits of the key can be recovered. See [3].
 *
 * Collecting n collisions with m bit long blinding value requires 2^(m-m/n)
 * observations on avarage.
 *
 * For example with 28 byte blinding to achieve 2 collisions the adversary has
 * to make 2^112 observations on avarage.
 *
 * (With the currently (as of 2017 April) known best algorithms breaking 2048
 * bit RSA requires approximately as much time as trying out 2^112 random keys.
 * Thus in this sense with 28 byte blinding the security is not reduced by
 * side-channel attacks like the one in [3])
 *
 * This countermeasure does not help if the key recovery is possible with a
 * single trace.
 */
#define RSA_EXPONENT_BLINDING 28

/*
 * Do an RSA private key operation
 */
int sc_mbedtls_rsa_private(sc_mbedtls_rsa_context *ctx,
                            int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
                            const unsigned char *input, unsigned char *output)
{
    int              ret;
    size_t           olen;
    sc_mbedtls_mpi  T, T1, T2;
    sc_mbedtls_mpi  P1, Q1, R;
    sc_mbedtls_mpi  D_blind;
    sc_mbedtls_mpi *D = &ctx->D;

    /* Make sure we have private key info, prevent possible misuse */
    if (/*ctx->P.p == NULL || ctx->Q.p == NULL || */ ctx->D.p == NULL)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    sc_mbedtls_mpi_init(&T);
    sc_mbedtls_mpi_init(&T1);
    sc_mbedtls_mpi_init(&T2);
    sc_mbedtls_mpi_init(&P1);
    sc_mbedtls_mpi_init(&Q1);
    sc_mbedtls_mpi_init(&R);

    if (f_rng != NULL) {
        sc_mbedtls_mpi_init(&D_blind);
    }

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_binary(&T, input, ctx->len));
    if (sc_mbedtls_mpi_cmp_mpi(&T, &ctx->N) >= 0) {
        ret = SC_MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
        goto cleanup;
    }

    if (f_rng != NULL) {
        /*
         * Blinding
         * T = T * Vi mod N
         */
        SC_MBEDTLS_MPI_CHK(rsa_prepare_blinding(ctx, f_rng, p_rng));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&T, &T, &ctx->Vi));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&T, &T, &ctx->N));

        /*
         * Exponent blinding
         */
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_sub_int(&P1, &ctx->P, 1));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_sub_int(&Q1, &ctx->Q, 1));

        /*
         * D_blind = ( P - 1 ) * ( Q - 1 ) * R + D
         */
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_fill_random(&R, RSA_EXPONENT_BLINDING, f_rng, p_rng));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&D_blind, &P1, &Q1));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&D_blind, &D_blind, &R));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_add_mpi(&D_blind, &D_blind, &ctx->D));

        D = &D_blind;
    }
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_exp_mod(&T, &T, D, &ctx->N, &ctx->RN));

    if (f_rng != NULL) {
        /*
         * Unblind
         * T = T * Vf mod N
         */
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mul_mpi(&T, &T, &ctx->Vf));
        SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_mod_mpi(&T, &T, &ctx->N));
    }

    olen = ctx->len;
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_write_binary(&T, output, olen));

cleanup:
    sc_mbedtls_mpi_free(&T);
    sc_mbedtls_mpi_free(&T1);
    sc_mbedtls_mpi_free(&T2);
    sc_mbedtls_mpi_free(&P1);
    sc_mbedtls_mpi_free(&Q1);
    sc_mbedtls_mpi_free(&R);

    if (f_rng != NULL) {
        sc_mbedtls_mpi_free(&D_blind);
    }

    if (ret != 0)
        return (SC_MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret);

    return (0);
}

/*
 * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function
 */
int sc_mbedtls_rsa_rsaes_pkcs1_v15_encrypt(sc_mbedtls_rsa_context *ctx,
                                            int (*f_rng)(void *, unsigned char *, size_t),
                                            void *p_rng, int mode, size_t ilen,
                                            const unsigned char *input, unsigned char *output)
{
    size_t         nb_pad, olen;
    int            ret;
    unsigned char *p = output;

    if (mode == SC_MBEDTLS_RSA_PRIVATE && ctx->padding != SC_MBEDTLS_RSA_PKCS_V15)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    // We don't check p_rng because it won't be dereferenced here
    if (f_rng == NULL || input == NULL || output == NULL)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    olen = ctx->len;

    /* first comparison checks for overflow */
    if (ilen + 11 < ilen || olen < ilen + 11)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    nb_pad = olen - 3 - ilen;

    *p++ = 0;
    if (mode == SC_MBEDTLS_RSA_PUBLIC) {
        *p++ = SC_MBEDTLS_RSA_CRYPT;

        while (nb_pad-- > 0) {
            int rng_dl = 100;

            do {
                ret = f_rng(p_rng, p, 1);
            } while (*p == 0 && --rng_dl && ret == 0);

            /* Check if RNG failed to generate data */
            if (rng_dl == 0 || ret != 0)
                return (SC_MBEDTLS_ERR_RSA_RNG_FAILED + ret);

            p++;
        }
    } else {
        *p++ = SC_MBEDTLS_RSA_SIGN;

        while (nb_pad-- > 0)
            *p++ = 0xFF;
    }

    *p++ = 0;
    memcpy(p, input, ilen);

    return ((mode == SC_MBEDTLS_RSA_PUBLIC)
                ? sc_mbedtls_rsa_public(ctx, output, output)
                : sc_mbedtls_rsa_private(ctx, NULL, p_rng, output, output));
}

/*
 * Add the message padding, then do an RSA operation
 */
int sc_mbedtls_rsa_pkcs1_encrypt(sc_mbedtls_rsa_context *ctx,
                                  int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
                                  int mode, size_t ilen, const unsigned char *input,
                                  unsigned char *output)
{
    int ret = SC_FAIL;
    switch (ctx->padding) {
        case SC_MBEDTLS_RSA_PKCS_V15:
            ret = sc_mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx, f_rng, p_rng, mode, ilen, input,
                                                          output);
            break;

        default:
            return (SC_MBEDTLS_ERR_RSA_INVALID_PADDING);
    }

    return ret;
}

/*
 * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
 */
int sc_mbedtls_rsa_rsaes_pkcs1_v15_decrypt(sc_mbedtls_rsa_context *ctx,
                                            int (*f_rng)(void *, unsigned char *, size_t),
                                            void *p_rng, int mode, size_t *olen,
                                            const unsigned char *input, unsigned char *output,
                                            size_t output_max_len)
{
    int            ret;
    size_t         ilen, pad_count = 0, i;
    unsigned char *p, bad, pad_done = 0;
    unsigned char  buf[SC_MBEDTLS_MPI_MAX_SIZE];

    if (mode == SC_MBEDTLS_RSA_PRIVATE && ctx->padding != SC_MBEDTLS_RSA_PKCS_V15)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    ilen = ctx->len;

    if (ilen < 16 || ilen > sizeof(buf))
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    ret = (mode == SC_MBEDTLS_RSA_PUBLIC) ? sc_mbedtls_rsa_public(ctx, input, buf)
                                       : sc_mbedtls_rsa_private(ctx, NULL, p_rng, input, buf);

    if (ret != 0)
        goto cleanup;

    p   = buf;
    bad = 0;

    /*
     * Check and get padding len in "constant-time"
     */
    bad |= *p++; /* First byte must be 0 */

    /* This test does not depend on secret data */
    if (mode == SC_MBEDTLS_RSA_PRIVATE) {
        bad |= *p++ ^ SC_MBEDTLS_RSA_CRYPT;

        /* Get padding len, but always read till end of buffer
         * (minus one, for the 00 byte) */
        for (i = 0; i < ilen - 3; i++) {
            pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1;
            pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
        }

        p += pad_count;
        bad |= *p++; /* Must be zero */
    } else {
        bad |= *p++ ^ SC_MBEDTLS_RSA_SIGN;

        /* Get padding len, but always read till end of buffer
         * (minus one, for the 00 byte) */
        for (i = 0; i < ilen - 3; i++) {
            pad_done |= (p[i] != 0xFF);
            pad_count += (pad_done == 0);
        }

        p += pad_count;
        bad |= *p++; /* Must be zero */
    }

    bad |= (pad_count < 8);

    if (bad) {
        ret = SC_MBEDTLS_ERR_RSA_INVALID_PADDING;
        goto cleanup;
    }

    if (ilen - (p - buf) > output_max_len) {
        ret = SC_MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
        goto cleanup;
    }

    *olen = ilen - (p - buf);
    memcpy(output, p, *olen);
    ret = 0;

cleanup:
    mbedtls_zeroize(buf, sizeof(buf));

    return (ret);
}

/*
 * Do an RSA operation, then remove the message padding
 */
int sc_mbedtls_rsa_pkcs1_decrypt(sc_mbedtls_rsa_context *ctx,
                                  int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
                                  int mode, size_t *olen, const unsigned char *input,
                                  unsigned char *output, size_t output_max_len)
{
    switch (ctx->padding) {
        case SC_MBEDTLS_RSA_PKCS_V15:
            return sc_mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx, f_rng, p_rng, mode, olen, input,
                                                           output, output_max_len);
        default:
            return (SC_MBEDTLS_ERR_RSA_INVALID_PADDING);
    }
}

/*
 * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function
 */
/*
 * Do an RSA operation to sign the message digest
 */
int sc_mbedtls_rsa_rsassa_pkcs1_v15_sign(sc_mbedtls_rsa_context *ctx,
                                          int (*f_rng)(void *, unsigned char *, size_t),
                                          void *p_rng, int mode, sc_mbedtls_md_type_t md_alg,
                                          unsigned int hashlen, const unsigned char *hash,
                                          unsigned char *sig)
{
    size_t                 nb_pad, olen, oid_size = 0;
    unsigned char *        p   = sig;
    const char *           oid = NULL;
    unsigned char          verif[256];
    unsigned char          sig_try[256];
    size_t                 i;
    unsigned char          diff;
    volatile unsigned char diff_no_optimize;
    int                    ret;

    if (mode == SC_MBEDTLS_RSA_PRIVATE && ctx->padding != SC_MBEDTLS_RSA_PKCS_V15)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    olen   = ctx->len;
    nb_pad = olen - 3;

    if (md_alg != SC_MBEDTLS_MD_NONE) {
        const sc_mbedtls_md_info_t *md_info = sc_mbedtls_md_info_from_type(md_alg);
        if (md_info == NULL)
            return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

        if (sc_mbedtls_oid_get_oid_by_md(md_alg, &oid, &oid_size) != 0)
            return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

        nb_pad -= 10 + oid_size;

        hashlen = sc_mbedtls_md_get_size(md_info);
    }

    nb_pad -= hashlen;

    if ((nb_pad < 8) || (nb_pad > olen))
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    *p++ = 0;
    *p++ = SC_MBEDTLS_RSA_SIGN;
    memset(p, 0xFF, nb_pad);
    p += nb_pad;
    *p++ = 0;

    if (md_alg == SC_MBEDTLS_MD_NONE) {
        memcpy(p, hash, hashlen);
    } else {
        /*
         * DigestInfo ::= SEQUENCE {
         *   digestAlgorithm DigestAlgorithmIdentifier,
         *   digest Digest }
         *
         * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
         *
         * Digest ::= OCTET STRING
         */
        *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
        *p++ = (unsigned char)(0x08 + oid_size + hashlen);
        *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
        *p++ = (unsigned char)(0x04 + oid_size);
        *p++ = MBEDTLS_ASN1_OID;
        *p++ = oid_size & 0xFF;
        memcpy(p, oid, oid_size);
        p += oid_size;
        *p++ = MBEDTLS_ASN1_NULL;
        *p++ = 0x00;
        *p++ = MBEDTLS_ASN1_OCTET_STRING;
        *p++ = hashlen;
        memcpy(p, hash, hashlen);
    }

    if (mode == SC_MBEDTLS_RSA_PUBLIC)
        return (sc_mbedtls_rsa_public(ctx, sig, sig));

    /*
     * In order to prevent Lenstra's attack, make the signature in a
     * temporary buffer and check it before returning it.
     */

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_rsa_private(ctx, NULL, p_rng, sig, sig_try));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_rsa_public(ctx, sig_try, verif));

    /* Compare in constant time just in case */
    for (diff = 0, i = 0; i < ctx->len; i++)
        diff |= verif[i] ^ sig[i];
    diff_no_optimize = diff;

    if (diff_no_optimize != 0) {
        ret = SC_MBEDTLS_ERR_RSA_PRIVATE_FAILED;
        goto cleanup;
    }

    memcpy(sig, sig_try, ctx->len);

cleanup:
    return (ret);
}

/*
 * Do an RSA operation to sign the message digest
 */
int sc_mbedtls_rsa_pkcs1_sign(sc_mbedtls_rsa_context *ctx,
                               int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode,
                               sc_mbedtls_md_type_t md_alg, unsigned int hashlen,
                               const unsigned char *hash, unsigned char *sig)
{
    switch (ctx->padding) {
        case SC_MBEDTLS_RSA_PKCS_V15:
            return sc_mbedtls_rsa_rsassa_pkcs1_v15_sign(ctx, f_rng, p_rng, mode, md_alg, hashlen,
                                                         hash, sig);

        default:
            return (SC_MBEDTLS_ERR_RSA_INVALID_PADDING);
    }
}

/*
 * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function
 */
int sc_mbedtls_rsa_rsassa_pkcs1_v15_verify(sc_mbedtls_rsa_context *ctx,
                                            int (*f_rng)(void *, unsigned char *, size_t),
                                            void *p_rng, int mode, sc_mbedtls_md_type_t md_alg,
                                            unsigned int hashlen, const unsigned char *hash,
                                            const unsigned char *sig)
{
    int                          ret;
    size_t                       len, siglen, asn1_len;
    unsigned char *              p, *p0, *end;
    sc_mbedtls_md_type_t        msg_md_alg;
    const sc_mbedtls_md_info_t *md_info;
    sc_mbedtls_asn1_buf         oid;
    unsigned char                buf[SC_MBEDTLS_MPI_MAX_SIZE];

    if (mode == SC_MBEDTLS_RSA_PRIVATE && ctx->padding != SC_MBEDTLS_RSA_PKCS_V15)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    siglen = ctx->len;

    if (siglen < 16 || siglen > sizeof(buf))
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);

    ret = (mode == SC_MBEDTLS_RSA_PUBLIC) ? sc_mbedtls_rsa_public(ctx, sig, buf)
                                       : sc_mbedtls_rsa_private(ctx, NULL, p_rng, sig, buf);

    if (ret != 0)
        return (ret);

    p = buf;

    if (*p++ != 0 || *p++ != SC_MBEDTLS_RSA_SIGN)
        return (SC_MBEDTLS_ERR_RSA_INVALID_PADDING);

    while (*p != 0) {
        if (p >= buf + siglen - 1 || *p != 0xFF)
            return (SC_MBEDTLS_ERR_RSA_INVALID_PADDING);
        p++;
    }
    p++; /* skip 00 byte */

    /* We've read: 00 01 PS 00 where PS must be at least 8 bytes */
    if (p - buf < 11)
        return (SC_MBEDTLS_ERR_RSA_INVALID_PADDING);

    len = siglen - (p - buf);

    if (len == hashlen && md_alg == SC_MBEDTLS_MD_NONE) {
        if (memcmp(p, hash, hashlen) == 0)
            return (0);
        else
            return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);
    }

    md_info = sc_mbedtls_md_info_from_type(md_alg);
    if (md_info == NULL)
        return (SC_MBEDTLS_ERR_RSA_BAD_INPUT_DATA);
    hashlen = sc_mbedtls_md_get_size(md_info);

    end = p + len;

    /*
     * Parse the ASN.1 structure inside the PKCS#1 v1.5 structure.
     * Insist on 2-byte length tags, to protect against variants of
     * Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification.
     */
    p0 = p;
    if ((ret = sc_mbedtls_asn1_get_tag(&p, end, &asn1_len,
                                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);
    if (p != p0 + 2 || asn1_len + 2 != len)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    p0 = p;
    if ((ret = sc_mbedtls_asn1_get_tag(&p, end, &asn1_len,
                                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);
    if (p != p0 + 2 || asn1_len + 6 + hashlen != len)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    p0 = p;
    if ((ret = sc_mbedtls_asn1_get_tag(&p, end, &oid.len, MBEDTLS_ASN1_OID)) != 0)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);
    if (p != p0 + 2)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    oid.p = p;
    p += oid.len;

    if (sc_mbedtls_oid_get_md_alg(&oid, &msg_md_alg) != 0)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    if (md_alg != msg_md_alg)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    /*
     * assume the algorithm parameters must be NULL
     */
    p0 = p;
    if ((ret = sc_mbedtls_asn1_get_tag(&p, end, &asn1_len, MBEDTLS_ASN1_NULL)) != 0)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);
    if (p != p0 + 2)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    p0 = p;
    if ((ret = sc_mbedtls_asn1_get_tag(&p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING)) != 0)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);
    if (p != p0 + 2 || asn1_len != hashlen)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    if (memcmp(p, hash, hashlen) != 0)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    p += hashlen;

    if (p != end)
        return (SC_MBEDTLS_ERR_RSA_VERIFY_FAILED);

    return (0);
}

/*
 * Do an RSA operation and check the message digest
 */
int sc_mbedtls_rsa_pkcs1_verify(sc_mbedtls_rsa_context *ctx,
                                 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
                                 int mode, sc_mbedtls_md_type_t md_alg, unsigned int hashlen,
                                 const unsigned char *hash, const unsigned char *sig)
{
    switch (ctx->padding) {
        case SC_MBEDTLS_RSA_PKCS_V15:
            return sc_mbedtls_rsa_rsassa_pkcs1_v15_verify(ctx, f_rng, p_rng, mode, md_alg, hashlen,
                                                           hash, sig);

        default:
            return (SC_MBEDTLS_ERR_RSA_INVALID_PADDING);
    }
}

/*
 * Copy the components of an RSA key
 */
int sc_mbedtls_rsa_copy(sc_mbedtls_rsa_context *dst, const sc_mbedtls_rsa_context *src)
{
    int ret;

    dst->ver = src->ver;
    dst->len = src->len;

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->N, &src->N));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->E, &src->E));

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->D, &src->D));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->P, &src->P));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->Q, &src->Q));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->DP, &src->DP));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->DQ, &src->DQ));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->QP, &src->QP));

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->RN, &src->RN));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->RP, &src->RP));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->RQ, &src->RQ));

    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->Vi, &src->Vi));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_copy(&dst->Vf, &src->Vf));

    dst->padding = src->padding;
    dst->hash_id = src->hash_id;

cleanup:
    if (ret != 0)
        sc_mbedtls_rsa_free(dst);

    return (ret);
}

/*
 * Free the components of an RSA key
 */
void sc_mbedtls_rsa_free(sc_mbedtls_rsa_context *ctx)
{
    sc_mbedtls_mpi_free(&ctx->Vi);
    sc_mbedtls_mpi_free(&ctx->Vf);
    sc_mbedtls_mpi_free(&ctx->RQ);
    sc_mbedtls_mpi_free(&ctx->RP);
    sc_mbedtls_mpi_free(&ctx->RN);
    sc_mbedtls_mpi_free(&ctx->QP);
    sc_mbedtls_mpi_free(&ctx->DQ);
    sc_mbedtls_mpi_free(&ctx->DP);
    sc_mbedtls_mpi_free(&ctx->Q);
    sc_mbedtls_mpi_free(&ctx->P);
    sc_mbedtls_mpi_free(&ctx->D);
    sc_mbedtls_mpi_free(&ctx->E);
    sc_mbedtls_mpi_free(&ctx->N);
}

#ifdef SC_RSA_SELF_TEST
//TODO hyphon
#include "crypto_sha1.h"

/*
 * Example RSA-1024 keypair, for test purposes
 */
#define KEY_LEN 128

#define RSA_N                                                                                      \
    "9292758453063D803DD603D5E777D788"                                                             \
    "8ED1D5BF35786190FA2F23EBC0848AEA"                                                             \
    "DDA92CA6C3D80B32C4D109BE0F36D6AE"                                                             \
    "7130B9CED7ACDF54CFC7555AC14EEBAB"                                                             \
    "93A89813FBF3C4F8066D2D800F7C38A8"                                                             \
    "1AE31942917403FF4946B0A83D3D3E05"                                                             \
    "EE57C6F5F5606FB5D4BC6CD34EE0801A"                                                             \
    "5E94BB77B07507233A0BC7BAC8F90F79"

#define RSA_E "10001"

#define RSA_D                                                                                      \
    "24BF6185468786FDD303083D25E64EFC"                                                             \
    "66CA472BC44D253102F8B4A9D3BFA750"                                                             \
    "91386C0077937FE33FA3252D28855837"                                                             \
    "AE1B484A8A9A45F7EE8C0C634F99E8CD"                                                             \
    "DF79C5CE07EE72C7F123142198164234"                                                             \
    "CABB724CF78B8173B9F880FC86322407"                                                             \
    "AF1FEDFDDE2BEB674CA15F3E81A1521E"                                                             \
    "071513A1E85B5DFA031F21ECAE91A34D"

#define RSA_P                                                                                      \
    "C36D0EB7FCD285223CFB5AABA5BDA3D8"                                                             \
    "2C01CAD19EA484A87EA4377637E75500"                                                             \
    "FCB2005C5C7DD6EC4AC023CDA285D796"                                                             \
    "C3D9E75E1EFC42488BB4F1D13AC30A57"

#define RSA_Q                                                                                      \
    "C000DF51A7C77AE8D7C7370C1FF55B69"                                                             \
    "E211C2B9E5DB1ED0BF61D0D9899620F4"                                                             \
    "910E4168387E3C30AA1E00C339A79508"                                                             \
    "8452DD96A9A5EA5D9DCA68DA636032AF"

#define RSA_DP                                                                                     \
    "C1ACF567564274FB07A0BBAD5D26E298"                                                             \
    "3C94D22288ACD763FD8E5600ED4A702D"                                                             \
    "F84198A5F06C2E72236AE490C93F07F8"                                                             \
    "3CC559CD27BC2D1CA488811730BB5725"

#define RSA_DQ                                                                                     \
    "4959CBF6F8FEF750AEE6977C155579C7"                                                             \
    "D8AAEA56749EA28623272E4F7D0592AF"                                                             \
    "7C1F1313CAC9471B5C523BFE592F517B"                                                             \
    "407A1BD76C164B93DA2D32A383E58357"

#define RSA_QP                                                                                     \
    "9AE7FBC99546432DF71896FC239EADAE"                                                             \
    "F38D18D2B2F0E2DD275AA977E2BF4411"                                                             \
    "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F"                                                             \
    "A74206CEC169D74BF5A8C50D6F48EA08"

#define PT_LEN 24
#define RSA_PT                                                                                     \
    "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF"                                             \
    "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD"

size_t                  len;
sc_mbedtls_rsa_context rsa;
unsigned char           rsa_plaintext[PT_LEN];
unsigned char           rsa_decrypted[PT_LEN];
unsigned char           rsa_ciphertext[KEY_LEN];
unsigned char           sha1sum[20];

/*
 * Checkup routine
 */
int sc_mbedtls_rsa_self_test(int verbose)
{
    int ret = 0;

    sc_mbedtls_rsa_init(&rsa, SC_MBEDTLS_RSA_PKCS_V15, 0);

    rsa.len = KEY_LEN;
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_string(&rsa.N, 16, RSA_N));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_string(&rsa.E, 16, RSA_E));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_string(&rsa.D, 16, RSA_D));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_string(&rsa.P, 16, RSA_P));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_string(&rsa.Q, 16, RSA_Q));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_string(&rsa.DP, 16, RSA_DP));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_string(&rsa.DQ, 16, RSA_DQ));
    SC_MBEDTLS_MPI_CHK(sc_mbedtls_mpi_read_string(&rsa.QP, 16, RSA_QP));

    if (verbose != 0)
        sc_mbedtls_printf("  RSA key validation: ");

    if (sc_mbedtls_rsa_check_pubkey(&rsa) != 0 || sc_mbedtls_rsa_check_privkey(&rsa) != 0) {
        if (verbose != 0)
            sc_mbedtls_printf("failed\n");

        return (1);
    }

    if (verbose != 0)
        sc_mbedtls_printf("passed\n  PKCS#1 encryption : ");

    memcpy(rsa_plaintext, RSA_PT, PT_LEN);

    if (sc_mbedtls_rsa_pkcs1_encrypt(&rsa, rsa_rand, NULL, SC_MBEDTLS_RSA_PUBLIC, PT_LEN,
                                      rsa_plaintext, rsa_ciphertext) != 0) {
        if (verbose != 0)
            sc_mbedtls_printf("failed\n");

        return (1);
    }

    if (verbose != 0)
        sc_mbedtls_printf("passed\n  PKCS#1 decryption : ");

    if (sc_mbedtls_rsa_pkcs1_decrypt(&rsa, rsa_rand, NULL, SC_MBEDTLS_RSA_PRIVATE, &len,
                                      rsa_ciphertext, rsa_decrypted, sizeof(rsa_decrypted)) != 0) {
        if (verbose != 0)
            sc_mbedtls_printf("failed\n");

        return (1);
    }

    if (memcmp(rsa_decrypted, rsa_plaintext, len) != 0) {
        if (verbose != 0)
            sc_mbedtls_printf("failed 2 %d\n", len);

        return (1);
    }

    if (verbose != 0)
        sc_mbedtls_printf("passed\n");

    if (verbose != 0)
        sc_mbedtls_printf("  PKCS#1 data sign  : ");

    sc_mbedtls_sha1(rsa_plaintext, PT_LEN, sha1sum);

    if (sc_mbedtls_rsa_pkcs1_sign(&rsa, rsa_rand, NULL, SC_MBEDTLS_RSA_PRIVATE, SC_MBEDTLS_MD_SHA1, 0,
                                   sha1sum, rsa_ciphertext) != 0) {
        if (verbose != 0)
            sc_mbedtls_printf("failed\n");

        return (1);
    }

    if (verbose != 0)
        sc_mbedtls_printf("passed\n  PKCS#1 sig. verify: ");

    if (sc_mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, SC_MBEDTLS_RSA_PUBLIC, SC_MBEDTLS_MD_SHA1, 0,
                                     sha1sum, rsa_ciphertext) != 0) {
        if (verbose != 0)
            sc_mbedtls_printf("failed\n");

        return (1);
    }

    if (verbose != 0)
        sc_mbedtls_printf("passed\n");

    if (verbose != 0)
        sc_mbedtls_printf("\n");

cleanup:
    sc_mbedtls_rsa_free(&rsa);
    return (ret);
}

#endif /* SC_RSA_SELF_TEST */
